package com.wutong.resonance.model.audio.tool;

import com.wutong.resonance.model.audio.AudioData;
import com.wutong.resonance.model.audio.AudioParams;
import com.wutong.resonance.model.exception.AudioPlayerException;
import com.wutong.resonance.model.interfaces.PluginProcessor;
import com.wutong.resonance.model.tool.PluginQueue;
import com.wutong.resonance.model.tool.ThreadPool;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import javax.sound.sampled.*;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 音频播放器。 用于播放音频文件，提供播放、暂停、恢复、停止和设置播放位置等功能。
 *
 * @author wutong
 */
@Slf4j
@Getter
public class AudioPlayer implements PluginProcessor {

    /**
     * 要播放的音频文件。
     */
    private final AudioFile audioFile;
    private final AudioParams audioParams;

    /**
     * 用于音频输出的 SourceDataLine。
     */
    private SourceDataLine sourceDataLine;

    /**
     * 音频格式。
     */
    private AudioFormat format;

    /**
     * 音频数据。
     */
    private byte[] data;

    private AudioData audioData;

    /**
     * 缓冲区大小。
     */
    private int bufferSize;

    /**
     * 当前帧位置。
     */
    private final AtomicLong framePosition = new AtomicLong(0);

    /**
     * 是否正在播放的标志。
     */
    private final AtomicBoolean playing = new AtomicBoolean(false);

    /**
     * 是否已暂停的标志。
     */
    private final AtomicBoolean paused = new AtomicBoolean(false);

    /**
     * 是否已请求停止的标志。
     */
    private final AtomicBoolean stopRequested = new AtomicBoolean(false);

    /**
     * 用于执行播放任务的线程池。
     */
    private final ThreadPool threadPool = ThreadPool.getInstance();

    /**
     * 播放任务的 Future 对象。
     */
    private Future<?> playTaskFuture;

    /**
     * 专门用于同步暂停和恢复的锁对象。
     */
    private final Object pauseLock = new Object();

    /**
     * 处理缓冲区
     */
    private final BlockingQueue<byte[]> processingBuffer;

    private final PluginQueue pluginQueue = new PluginQueue();

    /**
     * 构造函数。
     *
     * @param audioFile 要播放的音频文件。
     */
    public AudioPlayer(AudioFile audioFile, AudioParams audioParams) {
        this.audioFile = audioFile;
        this.audioParams = audioParams;
        // 初始缓冲区大小
        this.processingBuffer = new ArrayBlockingQueue<>(10);
        init();
    }

    /**
     * 构造函数。
     *
     * @param audioFile   要播放的音频文件。
     * @param audioParams 音频参数。
     * @param bufferSize  缓冲区大小。
     */
    public AudioPlayer(AudioFile audioFile, AudioParams audioParams, int bufferSize) {
        this.audioFile = audioFile;
        this.audioParams = audioParams;
        // 初始缓冲区大小
        this.processingBuffer = new ArrayBlockingQueue<>(bufferSize);
        init();
    }

    /**
     * 初始化音频播放器。 加载音频文件、获取音频格式、设置缓冲区大小和打开 SourceDataLine。
     *
     * @throws AudioPlayerException.AudioPlayerInitException 如果初始化失败。
     */
    private void init() {
        try {
            AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
            this.format = audioStream.getFormat();
            this.data = audioStream.readAllBytes();
            // 0.1秒缓冲区
            this.bufferSize = format.getFrameSize() * (int) format.getSampleRate() / 10;
            this.sourceDataLine = AudioSystem.getSourceDataLine(format);
            sourceDataLine.open(format);
        } catch (UnsupportedAudioFileException e) {
            log.error("音频播放器初始化失败，不支持的文件类型", e);
            throw new AudioPlayerException.AudioPlayerInitException("不支持的文件类型", e);
        } catch (IOException e) {
            log.error("音频播放器初始化失败，文件读取失败", e);
            throw new AudioPlayerException.AudioPlayerInitException("文件读取失败", e);
        } catch (LineUnavailableException e) {
            log.error("音频播放器初始化失败，音频输出设备不可用", e);
            throw new AudioPlayerException.AudioPlayerInitException("音频输出设备不可用", e);
        } catch (Exception e) {
            log.error("音频播放器初始化失败", e);
            throw new AudioPlayerException.AudioPlayerInitException("音频播放器初始化失败", e);
        }
    }

    /**
     * 开始播放音频。 如果当前没有播放，则启动新的播放任务。 如果当前已暂停，则恢复播放。
     */
    public void play() {
        if (!playing.get()) {
            playing.set(true);
            paused.set(false);
            stopRequested.set(false);
            playTaskFuture = threadPool.submit(this::playTask);
        } else if (paused.get()) {
            resume();
        }
    }

    /**
     * 播放任务。 从当前帧位置开始播放音频数据，直到播放结束、停止或暂停。
     */
    protected void playTask() {
        sourceDataLine.start();
        final int[] bytesRead = {(int) (framePosition.get() * format.getFrameSize())};

        // 生产者线程 - 将数据读入缓冲区
        threadPool.submit(() -> {
            while (playing.get() && bytesRead[0] < data.length && !stopRequested.get()) {
                if (paused.get()) {
                    try {
                        synchronized (pauseLock) {
                            pauseLock.wait();
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        // 结束生产者线程
                        return;
                    }
                }
                if (stopRequested.get()) {
                    return;
                }
                int bytesToRead = Math.min(bufferSize, data.length - bytesRead[0]);
                byte[] bufferChunk = new byte[bytesToRead];
                System.arraycopy(data, bytesRead[0], bufferChunk, 0, bytesToRead);
                try {
                    // 将数据块放入缓冲区，如果缓冲区满则阻塞
                    processingBuffer.put(bufferChunk);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    // 结束生产者线程
                    return;
                }
                bytesRead[0] += bytesToRead;
            }
        });

        // 消费者线程 - 从缓冲区读取、处理和播放数据
        while (playing.get() && !stopRequested.get()) {
            byte[] bufferChunk;
            try {
                // 从缓冲区取出数据块，如果缓冲区空则阻塞
                // 使用poll避免无限期阻塞
                bufferChunk = processingBuffer.poll(100, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }

            if (bufferChunk == null) {
                // 超时，检查播放状态
                if (!playing.get() || stopRequested.get()) {
                    break;
                }
                // 继续循环
                continue;
            }

            // 处理音频数据
            audioData = new AudioData(bufferChunk, audioParams);
            process(audioData);
            byte[] processedData = audioData.getByteData();

            // 写入SourceDataLine
            sourceDataLine.write(processedData, 0, processedData.length);

            // 更新帧位置（注意：这里假设所有数据都被立即播放，实际情况可能需要更精细的控制）
            framePosition.addAndGet(bufferChunk.length / format.getFrameSize());
        }

        sourceDataLine.stop();
        // 确保所有数据都被播放完毕
        sourceDataLine.flush();
        playing.set(false);
        paused.set(false);
        stopRequested.set(false);
        log.info("播放任务结束.");

    }

    /**
     * 暂停播放。 如果当前正在播放，则暂停播放。
     */
    public void pause() {
        if (playing.get() && !paused.get()) {
            paused.set(true);
            sourceDataLine.stop();
        }
    }

    /**
     * 恢复播放。 如果当前已暂停，则恢复播放。
     */
    public void resume() {
        if (playing.get() && paused.get()) {
            synchronized (pauseLock) {
                paused.set(false);
                pauseLock.notifyAll();
            }
            sourceDataLine.start();
        }
    }

    /**
     * 停止播放。 停止播放任务，并重置播放状态。
     */
    public void stop() {
        if (!stopRequested.compareAndSet(false, true)) {
            // 已经请求停止，直接返回
            return;
        }

        if (playTaskFuture != null) {
            // 尝试中断播放线程
            playTaskFuture.cancel(true);
        }

        playing.set(false);
        paused.set(false);
        framePosition.set(0);
        sourceDataLine.stop();
        sourceDataLine.flush();

        // 等待播放线程结束
        if (playTaskFuture != null) {
            try {
                // 检查任务是否被取消
                if (!playTaskFuture.isCancelled()) {
                    // 最多等待5秒
                    playTaskFuture.get(5, TimeUnit.SECONDS);
                } else {
                    log.info("播放任务被取消.");
                }
            } catch (Exception e) {
                log.warn("等待播放线程结束时发生异常", e);
            }
        }
        log.info("Stop requested.");
    }

    /**
     * 设置播放位置。
     *
     * @param frame 要设置的帧位置。
     */
    public void setFramePosition(long frame) {
        if (frame < 0 || frame * format.getFrameSize() > data.length) {
            log.warn("设置的帧位置超出范围：{}", frame);
            return; // 或者抛出异常
        }

        long currentFrame = framePosition.get();
        // 如果位置很接近，则不重新启动
        if (Math.abs(frame - currentFrame) <= 10) {
            return;
        }

        boolean wasPlaying = playing.get();
        if (wasPlaying) {
            // 先停止
            stop();
        }

        framePosition.set(frame);
        log.info("设置帧位置：{}", frame);

        if (wasPlaying) {
            // 重新开始
            play();
        }
    }

    /**
     * 获取当前帧位置。
     *
     * @return 当前帧位置。
     */
    public long getFramePosition() {
        return framePosition.get();
    }

    /**
     * 获取总帧数。
     *
     * @return 总帧数。
     */
    public long getTotalFrames() {
        return data.length / format.getFrameSize();
    }

    /**
     * 关闭音频播放器。 停止播放并释放资源。
     */
    public void close() {
        stop();
        if (sourceDataLine != null) {
            sourceDataLine.close();
        }
    }

    @Override
    public PluginQueue getPluginQueue() {
        return pluginQueue;
    }
}
